<template>
  <div class="qr-generator">
    <!-- 左侧配置面板 -->
    <div class="config-panel">
      <div class="panel-header">
        <h2>付款码生成</h2>
      </div>

      <div class="panel-content">
        <!-- 动态字段表单，基于模板 fields 数组 -->
        <template v-if="currentTemplateConfig && currentTemplateConfig.fields && currentTemplateConfig.fields.length">
          <div class="form-section">
            <div class="form-section-title">编辑字段</div>
            <a-divider class="section-divider" />
            <div
              class="field-item"
              v-for="field in currentTemplateConfig.fields"
              :key="field.key"
            >
              <label class="field-label">{{ field.label }}：</label>
              <input
                v-model="formData[field.key]"
                :type="field.type || 'text'"
                :placeholder="`请输入${field.label}`"
                class="form-input field-input"
              />
            </div>
          </div>
        </template>


        <!-- 收款信息设置 -->
        <div class="form-group">
          <label>收款信息</label>
          <div class="payment-tabs">
            <div class="tab-buttons">
              <button
                class="tab-btn"
                :class="{ active: activeTab === 'upload' }"
                @click="activeTab = 'upload'"
              >上传二维码</button>
              <button
                class="tab-btn"
                :class="{ active: activeTab === 'link' }"
                @click="activeTab = 'link'"
              >输入链接</button>
            </div>

            <!-- 上传二维码 -->
            <div class="tab-content" :class="{ active: activeTab === 'upload' }">
              <div class="upload-area" @click="triggerFileInput">
                <!-- 替换emoji为AntD图标 -->
                <UploadOutlined class="upload-icon" />
                <span>上传收款二维码图片</span>
                <input
                  ref="fileInput"
                  type="file"
                  accept="image/*"
                  hidden
                  @change="handleFileUpload"
                >
                <small>支持解码微信、支付宝、抖音等收款码</small>
              </div>
            </div>

            <!-- 输入链接 -->
            <div class="tab-content" :class="{ active: activeTab === 'link' }">
              <input
                v-model="formData.paymentUrl"
                type="text"
                placeholder="请输入收款链接"
                class="form-input"
              />
            </div>
          </div>
        </div>

        <!-- 模板选择 -->
        <div class="form-group">
          <label>付款码模板</label>
          <a-divider class="section-divider" />
          <div class="template-grid">
            <template v-if="templateList.length">
              <div
                v-for="tpl in templateList"
                :key="tpl.key"
                class="template-item"
                :class="{ active: selectedTemplate === tpl.key }"
              >
                <div class="template-preview" @click="selectTemplate(tpl.key)">
                  <div class="template-thumb template-thumb-image">
                    <img :src="tpl.config.thumbSrc || tpl.config.imageSrc || '/assets/images/placeholder_template.svg'" :alt="`${tpl.config.name || tpl.key}缩略图`" @error="($event) => { ($event.target as HTMLImageElement).src = '/assets/images/placeholder_template.svg' }" />
                    <div class="template-preview-overlay">
                      <span>点击预览</span>
                    </div>
                  </div>
                </div>
                <span class="template-name" @click="selectTemplate(tpl.key)">{{ tpl.config.name || tpl.key }}</span>
              </div>
            </template>
            <template v-else>
              <div style="color:#999;font-size:12px;">正在加载模板配置...</div>
            </template>
          </div>
        </div>
      </div>
    </div>

    <!-- 右侧预览区域 -->
    <div class="preview-panel">
      <div class="preview-content">
        <div class="preview-header">
          <h3>付款码预览</h3>
        </div>

        <div class="payment-preview">
          <div class="canvas-container">
            <canvas
              ref="canvasRef"
              :width="canvasWidth"
              :height="canvasHeight"
              class="payment-canvas"
            ></canvas>
          </div>
        </div>

        <div class="action-buttons">
          <button
            class="download-btn"
            :disabled="!canvasGenerated"
            @click="downloadImage"
          >
            <DownloadOutlined />
            下载付款码
          </button>
          <button
            class="download-btn"
            :disabled="!canvasGenerated"
            @click="copyToClipboard"
          >
            <CopyOutlined />
            复制图片
          </button>
        </div>
      </div>
    </div>
  </div>

  <!-- 模板预览模态框 -->
  <div class="template-modal" v-show="showTemplateModal" @click="hideTemplatePreview">
    <div class="template-modal-content" @click.stop>
      <div class="template-modal-header">
        <h3>{{ templatePreviewTitle }}</h3>
        <button class="template-modal-close" @click="hideTemplatePreview">×</button>
      </div>
      <div class="template-modal-body">
        <img :src="templatePreviewSrc" :alt="templatePreviewTitle" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, watch, onMounted, nextTick, computed } from 'vue'
import QRCode from 'qrcode'
import { UploadOutlined, DownloadOutlined, CopyOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'

// jsQR library loading and QR decode functionality
let jsQRLibrary: any = null
let jsQRLoadPromise: Promise<any> | null = null
let jsQRLoadAttempts = 0
const MAX_LOAD_ATTEMPTS = 3

const loadJsQRLibrary = async (): Promise<any> => {
  // Return cached library
  if (jsQRLibrary) {
    return jsQRLibrary
  }

  // Return ongoing load promise
  if (jsQRLoadPromise) {
    return jsQRLoadPromise
  }

  // Check if already loaded globally
  if ((window as any).jsQR) {
    jsQRLibrary = (window as any).jsQR
    console.log('jsQR library found in global scope')
    return jsQRLibrary
  }

  // Start loading
  jsQRLoadPromise = (async () => {
    jsQRLoadAttempts++
    console.log(`Loading jsQR library, attempt ${jsQRLoadAttempts}/${MAX_LOAD_ATTEMPTS}`)

    const cdnUrls = [
      'https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js',
      'https://unpkg.com/jsqr@1.4.0/dist/jsQR.js',
      'https://cdnjs.cloudflare.com/ajax/libs/jsQR/1.4.0/jsQR.min.js'
    ]

    for (const url of cdnUrls) {
      try {
        console.log(`Trying to load jsQR from: ${url}`)

        await new Promise((resolve, reject) => {
          // Remove existing script with same src
          const existingScript = document.querySelector(`script[src="${url}"]`)
          if (existingScript) {
            existingScript.remove()
          }

          const script = document.createElement('script')
          script.src = url
          script.onload = () => {
            console.log(`✓ jsQR successfully loaded from: ${url}`)
            resolve((window as any).jsQR)
          }
          script.onerror = () => {
            console.warn(`✗ Failed to load jsQR from ${url}`)
            reject(new Error(`Failed to load jsQR from ${url}`))
          }

          // Add timeout for loading
          setTimeout(() => {
            reject(new Error(`Timeout loading jsQR from ${url}`))
          }, 10000)

          document.head.appendChild(script)
        })

        if ((window as any).jsQR) {
          jsQRLibrary = (window as any).jsQR
          jsQRLoadPromise = null
          console.log('jsQR library successfully initialized')
          return jsQRLibrary
        }
      } catch (error) {
        console.warn(`Failed to load jsQR from ${url}:`, error)
        continue
      }
    }

    jsQRLoadPromise = null

    if (jsQRLoadAttempts < MAX_LOAD_ATTEMPTS) {
      console.log(`All CDN sources failed, retrying... (${jsQRLoadAttempts}/${MAX_LOAD_ATTEMPTS})`)
      // Recursive retry after delay
      await new Promise(resolve => setTimeout(resolve, 2000))
      return loadJsQRLibrary()
    } else {
      throw new Error(`Failed to load jsQR library after ${MAX_LOAD_ATTEMPTS} attempts`)
    }
  })()

  return jsQRLoadPromise
}

// 图像预处理函数：提高二维码识别成功率
const preprocessCanvas = (canvas: HTMLCanvasElement): HTMLCanvasElement[] => {
  const ctx = canvas.getContext('2d')
  if (!ctx) return [canvas]

  const results: HTMLCanvasElement[] = []

  // 原始图像
  results.push(canvas)

  // 增强对比度
  try {
    const enhancedCanvas = document.createElement('canvas')
    enhancedCanvas.width = canvas.width
    enhancedCanvas.height = canvas.height
    const enhancedCtx = enhancedCanvas.getContext('2d')!

    enhancedCtx.filter = 'contrast(150%) brightness(110%)'
    enhancedCtx.drawImage(canvas, 0, 0)
    results.push(enhancedCanvas)
  } catch (error) {
    console.warn('Enhanced contrast processing failed:', error)
  }

  // 灰度化处理
  try {
    const grayscaleCanvas = document.createElement('canvas')
    grayscaleCanvas.width = canvas.width
    grayscaleCanvas.height = canvas.height
    const grayscaleCtx = grayscaleCanvas.getContext('2d')!

    grayscaleCtx.filter = 'grayscale(100%) contrast(150%)'
    grayscaleCtx.drawImage(canvas, 0, 0)
    results.push(grayscaleCanvas)
  } catch (error) {
    console.warn('Grayscale processing failed:', error)
  }

  return results
}

// QR Code decoding function using jsQR library with enhanced algorithms
const decodeQRFromCanvas = async (canvas: HTMLCanvasElement): Promise<string | null> => {
  try {
    // Load jsQR library
    const jsQR = await loadJsQRLibrary()
    if (!jsQR) {
      throw new Error('jsQR library not available')
    }

    // 预处理图像以提高识别成功率
    const processedCanvases = preprocessCanvas(canvas)

    // 多种识别策略
    const strategies = [
      { inversionAttempts: "dontInvert" },
      { inversionAttempts: "onlyInvert" },
      { inversionAttempts: "attemptBoth" }
    ]

    // 对每个预处理后的图像尝试所有策略
    for (const processedCanvas of processedCanvases) {
      const ctx = processedCanvas.getContext('2d')
      if (!ctx) continue

      try {
        const imageData = ctx.getImageData(0, 0, processedCanvas.width, processedCanvas.height)

        for (const options of strategies) {
          try {
            const code = jsQR(imageData.data, imageData.width, imageData.height, options)
            if (code && code.data && code.data.trim()) {
              console.log('✓ QR Code detected:', code.data)
              return code.data.trim()
            }
          } catch (strategyError) {
            // 静默处理策略错误，继续尝试下一个
            continue
          }
        }
      } catch (imageError) {
        console.warn('Image processing error:', imageError)
        continue
      }
    }

    return null
  } catch (error) {
    console.error('QR decode error:', error)
    return null
  }
}

// Create canvas from image file
const createCanvasFromImage = (file: File): Promise<HTMLCanvasElement> => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    if (!ctx) {
      reject(new Error('无法创建canvas上下文'))
      return
    }

    img.onload = () => {
      canvas.width = img.width
      canvas.height = img.height
      ctx.drawImage(img, 0, 0)
      resolve(canvas)
    }

    img.onerror = () => reject(new Error('图片加载失败'))

    const reader = new FileReader()
    reader.onload = (e) => {
      img.src = e.target?.result as string
    }
    reader.onerror = () => reject(new Error('文件读取失败'))
    reader.readAsDataURL(file)
  })
}

// Process file for QR code detection
const processQRFile = async (file: File): Promise<{ success: boolean; result?: string; error?: string }> => {
  try {
    // Validate file type
    if (!file.type.startsWith('image/')) {
      return { success: false, error: '请选择图片文件' }
    }

    // Validate file size (max 10MB)
    const maxSize = 10 * 1024 * 1024
    if (file.size > maxSize) {
      return { success: false, error: '图片大小不能超过10MB' }
    }

    // Create canvas and decode
    const canvas = await createCanvasFromImage(file)
    const decodedContent = await decodeQRFromCanvas(canvas)

    if (decodedContent) {
      return { success: true, result: decodedContent }
    } else {
      return { success: false, error: '未检测到二维码，请确保图片清晰且包含有效二维码' }
    }
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : '处理文件时发生未知错误'
    }
  }
}

// 响应式数据
const formData = reactive<Record<string, any>>({
  companyName: '和县爱学虎教育咨询有限公司',
  qrCodeId: 'SPINTP100634552770702',
  paymentUrl: 'https://qr.alipay.com/fkx12345',
  showLogo: false,
  paymentTitle: '扫码付款',
  // showQrDebug: false 已移除
})

const activeTab = ref('upload')
const canvasRef = ref<HTMLCanvasElement>()
const fileInput = ref<HTMLInputElement>()
const canvasGenerated = ref(false)
const showTemplateModal = ref(false)
const templatePreviewTitle = ref<string>('斗拱模板预览')
const templatePreviewSrc = ref<string>('/assets/images/template_dougong.jpg')
const selectedTemplate = ref<string>('dougong')

// 模板二维码位置与尺寸配置类型
type QRSpec = { size: number; x: number; y: number }

// 根据选中模板提供二维码绘制参数
const getQRSpec = (): QRSpec => {
  const cfg = currentTemplateConfig.value
  if (!cfg) {
    const size = 140
    return { size, x: (canvasWidth - size) / 2, y: canvasHeight * 0.41 }
  }
  const { size, xAlignment, yRel, yOffset } = cfg.qr
  const x = xAlignment === 'center' ? (canvasWidth - size) / 2 : xAlignment === 'left' ? 0 : (canvasWidth - size)
  const y = canvasHeight * yRel + yOffset
  return { size, x, y }
}

// 选择模板并重绘画布
const selectTemplate = (tpl: string) => {
  selectedTemplate.value = tpl
  const cfgs = templateConfigs.value
  const cfg = cfgs ? cfgs[tpl] : null
  if (cfg && Array.isArray(cfg.fields)) {
    cfg.fields.forEach(f => {
      // 按字段提供的默认值应用，没有默认值则置空
      formData[f.key] = f.default ?? ''
    })
  }
  drawCanvas()
}
const canvasWidth = 300
const canvasHeight = 475

// 高清输出尺寸 - 用于下载和复制，保持原图质量
const highResScale = 4  // 4倍分辨率
const highResWidth = canvasWidth * highResScale
const highResHeight = canvasHeight * highResScale

// 绘制Canvas的核心函数
const drawCanvas = async () => {
  const canvas = canvasRef.value
  if (!canvas) return

  const ctx = canvas.getContext('2d')
  if (!ctx) return

  // 清除画布
  ctx.clearRect(0, 0, canvasWidth, canvasHeight)

  // 设置高清画布
  const dpr = window.devicePixelRatio || 1
  canvas.width = canvasWidth * dpr
  canvas.height = canvasHeight * dpr
  canvas.style.width = canvasWidth + 'px'
  canvas.style.height = canvasHeight + 'px'
  ctx.scale(dpr, dpr)

  try {
    // 加载并绘制背景模板图片
    await drawTemplateImage(ctx)

    // 在模板上绘制二维码
    await drawQRCodeOnTemplate(ctx)

    // 显示二维码ID仅由模板 fields 是否包含 qrCodeId 决定，同时需有输入值
    if (isFieldVisible('qrCodeId') && formData.qrCodeId) {
      drawQRCodeId(ctx)
    }

    canvasGenerated.value = true
  } catch (error) {
    console.error('绘制Canvas失败:', error)
  }
}

// 模板配置（从JSON加载）
interface QrConfig { size: number; xAlignment: 'center' | 'left' | 'right'; yRel: number; yOffset: number }
interface PaycodeField { key: string; label: string; default?: string; type?: string }
interface TemplateConfig { imageSrc: string; qr: QrConfig; name?: string; thumbSrc?: string; fields?: PaycodeField[] }
const templateConfigs = ref<Record<string, TemplateConfig> | null>(null)
const currentTemplateConfig = computed<TemplateConfig | null>(() => {
  const cfg = templateConfigs.value
  return cfg ? cfg[selectedTemplate.value] : null
})

// 供模板选择区域遍历渲染使用
const templateList = computed(() => {
  const cfgs = templateConfigs.value
  if (!cfgs) return [] as Array<{ key: string; config: TemplateConfig }>
  return Object.entries(cfgs).map(([key, config]) => ({ key, config }))
})

// 判断字段是否存在于当前模板的 fields 中（用于绘制控制）。
const isFieldVisible = (key: string): boolean => {
  const cfg = currentTemplateConfig.value
  if (!cfg || !Array.isArray(cfg.fields)) return false
  return cfg.fields.some(f => f.key === key)
}

// 新增：从配置文件加载左侧表单默认值
interface PaycodeDefaults {
  companyName: string
  qrCodeId: string
  paymentUrl: string

  showLogo: boolean
  paymentTitle: string
  selectedTemplate?: string
}
const loadPaycodeDefaults = async () => {
  try {
    const res = await fetch('/assets/config/paycode-defaults.json', { cache: 'no-cache' })
    if (!res.ok) return
    const contentType = res.headers.get('content-type') || ''
    // 当 dev server 对缺失文件返回 index.html (text/html) 时，跳过解析
    if (!contentType.includes('application/json')) return
    const data: Partial<PaycodeDefaults> = await res.json()
    if (data.companyName !== undefined) formData.companyName = data.companyName
    if (data.qrCodeId !== undefined) formData.qrCodeId = data.qrCodeId
    if (data.paymentUrl !== undefined) formData.paymentUrl = data.paymentUrl

    if (data.showLogo !== undefined) formData.showLogo = data.showLogo
    if (data.paymentTitle !== undefined) formData.paymentTitle = data.paymentTitle
    if (data.selectedTemplate) selectTemplate(data.selectedTemplate)
  } catch (e) {
    console.warn('默认配置未找到或不是JSON，已跳过', e)
  }
}

const loadTemplateConfigs = async () => {
  try {
    const res = await fetch('/assets/config/paycode-templates.json', { cache: 'no-cache' })
    if (!res.ok) throw new Error(`load config failed: ${res.status}`)
    templateConfigs.value = await res.json()
  } catch (e) {
    console.error('加载模板配置失败', e)
    message.error('加载模板配置失败，请刷新页面重试')
  }
}

onMounted(() => {
  loadTemplateConfigs()
  loadPaycodeDefaults()
})


// 绘制模板图片背景（使用配置里的imageSrc）
const drawTemplateImage = async (ctx: CanvasRenderingContext2D) => {
  return new Promise<void>((resolve) => {
    const img = new Image()
    const cfg = currentTemplateConfig.value
    img.onload = () => {
      const imgRatio = img.width / img.height
      const canvasRatio = canvasWidth / canvasHeight
      let drawWidth = canvasWidth
      let drawHeight = canvasHeight
      let drawX = 0
      let drawY = 0
      if (imgRatio > canvasRatio) {
        drawWidth = canvasHeight * imgRatio
        drawX = (canvasWidth - drawWidth) / 2
      } else {
        drawHeight = canvasWidth / imgRatio
        drawY = (canvasHeight - drawHeight) / 2
      }
      ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight)
      drawTextOnTemplate(ctx)
      resolve()
    }
    img.onerror = () => {
      const anyImg = img as any
      if (!anyImg._fallbackTried) {
        anyImg._fallbackTried = true
        img.src = '/assets/images/placeholder_template.svg'
        return
      }
      console.error('加载模板图片失败，已尝试占位图兜底')
      ctx.fillStyle = '#1E88E5'
      ctx.fillRect(0, 0, canvasWidth, canvasHeight)
      ctx.fillStyle = '#ffffff'
      ctx.font = 'bold 24px "Microsoft YaHei"'
      ctx.textAlign = 'center'
      ctx.fillText('模板加载失败', canvasWidth / 2, canvasHeight / 2)
      resolve()
    }
    img.src = cfg?.imageSrc || '/assets/images/template_dougong.jpg'
  })
}

// 文本绘制遵循配置开关
const drawTextOnTemplate = (ctx: CanvasRenderingContext2D) => {
  if (!isFieldVisible('companyName')) return
  ctx.save()
  if (formData.companyName) {
    ctx.fillStyle = '#FFFFFF'
    ctx.font = 'normal 16px "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", Arial, sans-serif'
    ctx.textAlign = 'center'
    const maxWidth = canvasWidth - 30
    const lines = wrapText(ctx, formData.companyName, maxWidth)
    const lineHeight = 20
    const startY = canvasHeight - 80
    lines.forEach((line, index) => {
      ctx.fillText(line, canvasWidth / 2, startY + index * lineHeight)
    })
  }
  ctx.restore()
}

// 绘制二维码ID遵循配置开关
const drawQRCodeId = (ctx: CanvasRenderingContext2D) => {
  if (!isFieldVisible('qrCodeId')) return
  ctx.fillStyle = '#666666'
  ctx.font = 'bold 10px monospace'
  ctx.textAlign = 'center'
  const { y, size } = getQRSpec()
  const idY = y + size + 13
  ctx.fillText(formData.qrCodeId, canvasWidth / 2, idY)
}


// 在普通/高清绘制里仍按配置判断
const drawQRCodeOnTemplate = async (ctx: CanvasRenderingContext2D) => {
  if (!formData.paymentUrl) return
  try {
    const qrDataURL = await QRCode.toDataURL(formData.paymentUrl, {
      width: 150,
      margin: 1,
      color: { dark: '#000000', light: '#ffffff' }
    })
    return new Promise<void>((resolve) => {
      const img = new Image()
      img.onload = () => {
        const { size, x, y } = getQRSpec()
        ctx.drawImage(img, x, y, size, size)
        // 调试定位框功能已移除
        resolve()
      }
      img.onerror = () => { resolve() }
      img.src = qrDataURL
    })
  } catch {
    // ignore
  }
}

// 在主画布与高清画布调用处，都用配置判断是否绘制二维码ID
  const drawQRDebugOverlay = (ctx: CanvasRenderingContext2D) => {
    const { size, x, y } = getQRSpec()
    ctx.save()
    ctx.strokeStyle = 'rgba(255, 0, 0, 0.9)'
    ctx.setLineDash([5, 3])
    ctx.lineWidth = 2
    ctx.strokeRect(x, y, size, size)
    // 十字中心线
    ctx.beginPath()
    ctx.moveTo(x, y + size / 2)
    ctx.lineTo(x + size, y + size / 2)
    ctx.moveTo(x + size / 2, y)
    ctx.lineTo(x + size / 2, y + size)
  ctx.stroke()
  ctx.restore()
}


// 绘制顶部区域
const drawTopSection = (ctx: CanvasRenderingContext2D) => {
  // 顶部白色背景
  ctx.fillStyle = '#ffffff'
  ctx.fillRect(0, 0, canvasWidth, 120)

  if (formData.showLogo) {
    // 绘制D Logo - 参考模板样式
    const logoSize = 60
    const logoX = 80
    const logoY = 30

    // 绘制蓝色D Logo背景
    ctx.fillStyle = '#1976d2'
    ctx.fillRect(logoX, logoY, logoSize, logoSize)

    // 绘制白色D字母
    ctx.fillStyle = '#ffffff'
    ctx.font = 'bold 40px Arial'
    ctx.textAlign = 'center'
    ctx.fillText('D', logoX + logoSize/2, logoY + logoSize/2 + 14)

    // 绘制"斗拱"文字 - 更大更醒目
    ctx.fillStyle = '#1976d2'
    ctx.font = 'bold 50px "Microsoft YaHei", Arial'
    ctx.fillText('斗拱', logoX + logoSize + 40, logoY + logoSize/2 + 18)
  }
}

// 绘制主体区域
const drawMainSection = async (ctx: CanvasRenderingContext2D) => {
  // 主体蓝色渐变背景 - 参考模板的蓝色渐变
  const gradient = ctx.createLinearGradient(0, 120, 0, 460)
  gradient.addColorStop(0, '#2196F3')
  gradient.addColorStop(0.3, '#1976D2')
  gradient.addColorStop(0.7, '#1565C0')
  gradient.addColorStop(1, '#0D47A1')
  ctx.fillStyle = gradient
  ctx.fillRect(0, 120, canvasWidth, 340)

  // 绘制装饰花纹/图案
  await drawDecorationPattern(ctx)

  // 绘制自定义标题（默认"扫码付款"）
  ctx.fillStyle = '#ffffff'
  ctx.font = 'bold 48px "Microsoft YaHei", Arial'
  ctx.textAlign = 'center'
  ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'
  ctx.shadowBlur = 4
  ctx.shadowOffsetX = 2
  ctx.shadowOffsetY = 2
  ctx.fillText(formData.paymentTitle, canvasWidth / 2, 190)

  // 重置阴影
  ctx.shadowColor = 'transparent'
  ctx.shadowBlur = 0
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0

  // 绘制大尺寸二维码容器
  const qrContainerX = 40
  const qrContainerY = 220
  const qrContainerWidth = 240
  const qrContainerHeight = 180

  // 白色圆角背景 - 更大的圆角
  ctx.fillStyle = '#ffffff'
  roundRect(ctx, qrContainerX, qrContainerY, qrContainerWidth, qrContainerHeight, 20)
  ctx.fill()

  // 绘制二维码或占位符
  if (formData.paymentUrl) {
    await drawQRCode(ctx, qrContainerX + 45, qrContainerY + 15)
  } else {
    // 绘制占位符
    ctx.fillStyle = '#f8f8f8'
    ctx.fillRect(qrContainerX + 45, qrContainerY + 15, 150, 150)
    ctx.strokeStyle = '#e0e0e0'
    ctx.lineWidth = 2
    ctx.strokeRect(qrContainerX + 45, qrContainerY + 15, 150, 150)

    ctx.fillStyle = '#666666'
    ctx.font = '40px Arial'
    ctx.textAlign = 'center'
    ctx.fillText('📱', qrContainerX + 120, qrContainerY + 75)
    ctx.font = '14px Arial'
    ctx.fillText('请填写左侧信息并生成', qrContainerX + 120, qrContainerY + 100)
  }

  // 绘制二维码ID - 在二维码下方（受配置 fields 控制）
  if (isFieldVisible('qrCodeId') && formData.qrCodeId) {
    ctx.fillStyle = '#333333'
    ctx.font = 'bold 14px monospace'
    ctx.textAlign = 'center'
    ctx.fillText(formData.qrCodeId, qrContainerX + 120, qrContainerY + 175)
  }

  // 绘制公司名称 - 在蓝色区域下方（受配置 fields 控制）
  if (isFieldVisible('companyName') && formData.companyName) {
    ctx.fillStyle = '#ffffff'
    ctx.font = 'bold 20px "Microsoft YaHei", Arial'
    ctx.textAlign = 'center'

    // 处理长文本换行
    const maxWidth = 280
    const lines = wrapText(ctx, formData.companyName, maxWidth)
    const lineHeight = 24
    const startY = 430

    lines.forEach((line, index) => {
      ctx.fillText(line, canvasWidth / 2, startY + index * lineHeight)
    })
  }
}

// 绘制底部支付图标区域
const drawBottomSection = (ctx: CanvasRenderingContext2D) => {
  // 底部浅灰色背景
  ctx.fillStyle = '#f5f5f5'
  ctx.fillRect(0, 460, canvasWidth, 100)

  // 绘制精美的支付图标 - 参考模板设计
  const iconSize = 55
  const iconY = 480
  const spacing = 15
  const totalWidth = 4 * iconSize + 3 * spacing
  const startX = (canvasWidth - totalWidth) / 2

  // 微信支付图标 - 绿色圆形带对勾
  drawPaymentIcon(ctx, startX, iconY, iconSize, '#07C160', '✓', '#ffffff', 'bold 28px Arial')

  // 支付宝图标 - 蓝色圆形带"支"字
  drawPaymentIcon(ctx, startX + iconSize + spacing, iconY, iconSize, '#1677FF', '支', '#ffffff', 'bold 22px "Microsoft YaHei"')

  // 银联图标 - 红色方形带"UnionPay"文字
  drawUnionPayIcon(ctx, startX + 2 * (iconSize + spacing), iconY, iconSize)

  // 其他支付图标 - 蓝色圆形
  drawPaymentIcon(ctx, startX + 3 * (iconSize + spacing), iconY, iconSize, '#00BFFF', '◯', '#ffffff', '24px Arial')
}

// 绘制二维码
const drawQRCode = async (ctx: CanvasRenderingContext2D, x: number, y: number) => {
  try {
    const qrDataURL = await QRCode.toDataURL(formData.paymentUrl, {
      width: 150,
      margin: 1,
      color: {
        dark: '#000000',
        light: '#ffffff'
      }
    })

    return new Promise<void>((resolve) => {
      const img = new Image()
      img.onload = () => {
        ctx.drawImage(img, x, y, 150, 150)
        resolve()
      }
      img.onerror = () => {
        // 绘制错误占位符
        ctx.fillStyle = '#ff0000'
        ctx.font = '12px Arial'
        ctx.textAlign = 'center'
        ctx.fillText('二维码加载失败', x + 75, y + 75)
        resolve()
      }
      img.src = qrDataURL
    })
  } catch (error) {
    console.error('生成二维码失败:', error)
    // 绘制错误占位符
    ctx.fillStyle = '#ff0000'
    ctx.font = '12px Arial'
    ctx.textAlign = 'center'
    ctx.fillText('二维码生成失败', x + 75, y + 75)
  }
}

// 工具函数：绘制圆角矩形
const roundRect = (ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number) => {
  ctx.beginPath()
  ctx.moveTo(x + radius, y)
  ctx.arcTo(x + width, y, x + width, y + height, radius)
  ctx.arcTo(x + width, y + height, x, y + height, radius)
  ctx.arcTo(x, y + height, x, y, radius)
  ctx.arcTo(x, y, x + width, y, radius)
  ctx.closePath()
}

// 工具函数：绘制圆形
const drawCircle = (ctx: CanvasRenderingContext2D, x: number, y: number, radius: number) => {
  ctx.beginPath()
  ctx.arc(x, y, radius, 0, 2 * Math.PI)
  ctx.fill()
}

// 绘制装饰花纹图案
const drawDecorationPattern = async (ctx: CanvasRenderingContext2D) => {
  // 绘制简单的装饰图案 - 类似模板中的流线型设计
  ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'
  ctx.lineWidth = 3

  // 绘制几条优雅的曲线作为装饰
  for (let i = 0; i < 6; i++) {
    ctx.beginPath()
    const startY = 140 + i * 50
    const amplitude = 20 + i * 5

    ctx.moveTo(-50, startY)
    for (let x = -50; x <= canvasWidth + 50; x += 10) {
      const y = startY + Math.sin((x + i * 30) * 0.01) * amplitude
      ctx.lineTo(x, y)
    }
    ctx.stroke()
  }
}

// 绘制支付图标的通用函数
const drawPaymentIcon = (ctx: CanvasRenderingContext2D, x: number, y: number, size: number, bgColor: string, text: string, textColor: string, font: string) => {
  // 绘制圆形背景
  ctx.fillStyle = bgColor
  drawCircle(ctx, x + size/2, y + size/2, size/2)

  // 添加阴影效果
  ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'
  ctx.shadowBlur = 6
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 3
  drawCircle(ctx, x + size/2, y + size/2, size/2)

  // 重置阴影
  ctx.shadowColor = 'transparent'
  ctx.shadowBlur = 0
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0

  // 绘制文字
  ctx.fillStyle = textColor
  ctx.font = font
  ctx.textAlign = 'center'
  ctx.fillText(text, x + size/2, y + size/2 + 8)
}

// 绘制银联特殊图标（方形）
const drawUnionPayIcon = (ctx: CanvasRenderingContext2D, x: number, y: number, size: number) => {
  // 绘制红色方形背景
  ctx.fillStyle = '#E4393C'
  roundRect(ctx, x, y, size, size, 8)
  ctx.fill()

  // 添加阴影
  ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'
  ctx.shadowBlur = 6
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 3
  roundRect(ctx, x, y, size, size, 8)
  ctx.fill()

  // 重置阴影
  ctx.shadowColor = 'transparent'
  ctx.shadowBlur = 0
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0

  // 绘制"UnionPay"文字
  ctx.fillStyle = '#ffffff'
  ctx.font = 'bold 8px Arial'
  ctx.textAlign = 'center'
  ctx.fillText('UnionPay', x + size/2, y + size/2 + 2)
}

// 工具函数：文本换行
const wrapText = (ctx: CanvasRenderingContext2D, text: string, maxWidth: number): string[] => {
  const words = text.split('')
  const lines: string[] = []
  let currentLine = ''

  for (const word of words) {
    const testLine = currentLine + word
    const metrics = ctx.measureText(testLine)

    if (metrics.width > maxWidth && currentLine !== '') {
      lines.push(currentLine)
      currentLine = word
    } else {
      currentLine = testLine
    }
  }

  lines.push(currentLine)
  return lines
}

// 事件处理函数
const triggerFileInput = () => {
  fileInput.value?.click()
}

const handleFileUpload = async (event: Event) => {
  const file = (event.target as HTMLInputElement).files?.[0]
  if (!file) return

  console.log('上传文件:', file.name)

  try {
    // 显示解码中状态
    const uploadArea = document.querySelector('.upload-area')
    const originalText = uploadArea?.querySelector('span')?.textContent
    if (uploadArea?.querySelector('span')) {
      uploadArea.querySelector('span')!.textContent = '正在解码二维码...'
    }

    // 解码二维码
    const result = await processQRFile(file)

    if (result.success && result.result) {
      // 解码成功，自动填充收款链接
      formData.paymentUrl = result.result

      // 自动切换到输入链接tab
      activeTab.value = 'link'

      // 显示成功提示
      if (uploadArea?.querySelector('span')) {
        uploadArea.querySelector('span')!.textContent = '✓ 解码成功，已自动填充收款链接'
        setTimeout(() => {
          if (uploadArea?.querySelector('span')) {
            uploadArea.querySelector('span')!.textContent = originalText || '上传收款二维码图片'
          }
        }, 3000)
      }

      // 自动重新生成付款码
      setTimeout(() => {
        generatePaymentCode()
      }, 500)

      console.log('✓ 二维码解码成功:', result.result)
    } else {
      // 解码失败
      console.warn('✗ 二维码解码失败:', result.error)
      message.error(`解码失败: ${result.error || '未知错误'}`)

      // 恢复原始文本
      if (uploadArea?.querySelector('span')) {
        uploadArea.querySelector('span')!.textContent = originalText || '上传收款二维码图片'
      }
    }
  } catch (error) {
    console.error('文件处理错误:', error)
    message.error('文件处理失败，请重试')

    // 恢复原始文本
    const uploadArea = document.querySelector('.upload-area')
    const originalText = '上传收款二维码图片'
    if (uploadArea?.querySelector('span')) {
      uploadArea.querySelector('span')!.textContent = originalText
    }
  }

  // 清除文件输入，允许重复上传同一文件
  ;(event.target as HTMLInputElement).value = ''
}

const generatePaymentCode = () => {
  drawCanvas()
}

// 模板预览相关方法
const showTemplatePreview = (src: string = '/assets/images/template_dougong.jpg', title: string = '斗拱模板预览') => {
  templatePreviewSrc.value = src
  templatePreviewTitle.value = title
  showTemplateModal.value = true
}

const hideTemplatePreview = () => {
  showTemplateModal.value = false
}

// 生成高清Canvas
const generateHighResCanvas = async () => {
  const highResCanvas = document.createElement('canvas')
  const ctx = highResCanvas.getContext('2d')
  if (!ctx) return null

  // 设置高清画布尺寸
  highResCanvas.width = highResWidth
  highResCanvas.height = highResHeight

  // 按高清比例缩放所有绘制操作
  ctx.scale(highResScale, highResScale)

  try {
    // 绘制模板图片（已包含文字元素）
    await drawTemplateImage(ctx)

    // 绘制二维码
    await drawQRCodeOnTemplate(ctx)

    // 显示二维码ID仅由模板 fields 是否包含 qrCodeId 决定，同时需有输入值
    if (isFieldVisible('qrCodeId') && formData.qrCodeId) {
      drawQRCodeId(ctx)
    }

    return highResCanvas
  } catch (error) {
    console.error('生成高清Canvas失败:', error)
    return null
  }
}

// 下载功能 - 使用高清Canvas
const downloadImage = async () => {
  const highResCanvas = await generateHighResCanvas()
  if (!highResCanvas) return

  highResCanvas.toBlob((blob) => {
    if (!blob) return

    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `付款码_${formData.companyName}_${Date.now()}.png`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
    // 下载成功提示
    message.success('图片已下载')
  }, 'image/png')
}

// 复制到剪贴板 - 使用高清Canvas
const copyToClipboard = async () => {
  const highResCanvas = await generateHighResCanvas()
  if (!highResCanvas) return

  try {
    highResCanvas.toBlob(async (blob) => {
      if (!blob) return

      const item = new ClipboardItem({ 'image/png': blob })
      await navigator.clipboard.write([item])
      // 替换 alert 为 message.success
      message.success('高清图片已复制到剪贴板')
      // TODO: alert改为toast提示
    }, 'image/png')
  } catch (error) {
    console.error('复制失败:', error)
  }
}


// 监听表单数据变化，自动重新绘制
watch(formData, () => {
  drawCanvas()
}, { deep: true })

// 组件挂载后初始化
onMounted(async () => {
  await nextTick()
  drawCanvas()
})
</script>

<style scoped>
.qr-generator {
  display: flex;
  width: 100vw;
  height: 100vh;
  background: #f0f2f5;
  padding: 0;
  margin: 0;
  gap: 0;
  box-sizing: border-box;
  overflow: hidden;
  position: fixed;
  top: 0;
  left: 0;
}

.config-panel {
  flex: 0 0 50%;
  width: 50%;
  background: white;
  border-right: 1px solid #e0e0e0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.panel-header {
  padding: 20px 30px 16px;
  border-bottom: 1px solid #e0e0e0;
  background: white;
  color: #333;
}

.panel-header h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
  color: #333;
}

.panel-content {
  flex: 1;
  padding: 40px 50px 30px;
  overflow-y: auto;
  overflow-x: hidden;
}

.panel-content::-webkit-scrollbar {
  width: 6px;
}

.panel-content::-webkit-scrollbar-track {
  background: transparent;
}

.panel-content::-webkit-scrollbar-thumb {
  background: #d0d0d0;
  border-radius: 3px;
}

.panel-content::-webkit-scrollbar-thumb:hover {
  background: #b0b0b0;
}

.form-group {
  width: 500px;
  margin-bottom: 24px;
}

.form-group:last-child {
  margin-bottom: 0;
}

.form-group label {
  display: block;
  margin: 62px 0 4px 0;
  font-weight: 700;
  font-size: 18px;
}

/* --- Dynamic Fields Section: title and inline layout --- */
.form-section {
  width: 500px;
  margin-bottom: 24px;
}

.form-section-title {
  display: block;
  margin-bottom: 8px;
  font-weight: 700;
  font-size: 18px; /* same as .form-group label (e.g., 当前“公司名称”的字号) */
}

.field-item {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 12px 0;
}

.field-label {
  flex: 0 0 80px; /* fixed label width to align inputs */
  font-size: 14px; /* regular text size */
  font-weight: 400;
  color: #555;
}

/* Override default input spacing inside field rows */
.field-input {
  flex: 1;
  margin: 0; /* cancel .form-input margin to keep inline */
  width: auto; /* allow flex to control width */
  min-width: 0; /* prevent overflow in flex */
}

.form-input {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
  transition: border-color 0.2s, box-shadow 0.2s;
  box-sizing: border-box;
}

.form-input:focus {
  outline: none;
  border-color: #4caf50;
  box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.1);
}

.payment-tabs {
  margin-top: 8px;
}

.tab-buttons {
  display: flex;
  border-bottom: 1px solid #e0e0e0;
  margin: 17px 0 10px 30px;
}

.tab-btn {
  padding: 8px 16px;
  border: none;
  background: transparent;
  color: #666;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.2s;
}

.tab-btn.active {
  color: #4caf50;
  border-bottom-color: #4caf50;
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}

.color-group {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.color-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.color-item span {
  font-size: 14px;
  color: #6b7280;
}

.color-picker {
  display: flex;
  align-items: center;
  gap: 8px;
}

.color-picker input[type="color"] {
  width: 40px;
  height: 32px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

.color-label {
  font-family: monospace;
  font-size: 12px;
  color: #9ca3af;
}

.logo-upload {
  width: 100%;
}

.upload-area {
  border: 1px dashed #ccc;
  border-radius: 4px;
  padding: 20px;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s;
  background: #fafafa;
}

.upload-area:hover {
  border-color: #4caf50;
  background: #f5f5f5;
}

.upload-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.upload-area span {
  font-size: 14px;
  color: #6b7280;
}

.upload-area small {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
  display: block;
}

.template-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 12px;
  margin-top: 12px;
}

.template-item {
  text-align: center;
  cursor: pointer;
  transition: all 0.2s;
}

.template-item.active .template-preview {
  border-color: #4caf50;
  box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.1);
}

.template-preview {
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 8px;
  transition: all 0.2s;
  cursor: pointer;
  position: relative;
}

.template-preview:hover {
  border-color: #ccc;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.template-thumb {
  width: 100px;
  height: 160px;
  background: linear-gradient(135deg, #1976d2 0%, #42a5f5 100%);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: bold;
  margin: 0 auto;
}

.template-thumb-image {
  background: none !important;
  padding: 0;
  overflow: hidden;
}

.template-thumb-image {
  position: relative;
}

.template-thumb-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 6px;
}

.template-preview-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.2s;
  font-size: 12px;
}

.template-thumb-image:hover .template-preview-overlay {
  opacity: 1;
}

/* 模板预览模态框样式 */
.template-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10000;
}

.template-modal-content {
  background: white;
  border-radius: 8px;
  max-width: 90vw;
  max-height: 90vh;
  overflow: hidden;
  position: relative;
}

.template-modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px 16px;
  border-bottom: 1px solid #e0e0e0;
}

.template-modal-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  color: #333;
}

.template-modal-close {
  background: none;
  border: none;
  font-size: 24px;
  color: #666;
  cursor: pointer;
  padding: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: all 0.2s;
}

.template-modal-close:hover {
  background: #f5f5f5;
  color: #333;
}

.template-modal-body {
  padding: 20px 24px 24px;
  text-align: center;
}

.template-modal-body img {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}

.template-name {
  font-size: 12px;
  color: #666;
}

.additional-settings {
  margin-top: 12px;
}

.setting-item {
  margin-bottom: 12px;
}

.checkbox-label {
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: 14px;
  color: #333;
}

.checkbox-label input[type="checkbox"] {
  margin-right: 8px;
  width: 16px;
  height: 16px;
}

.platform-selector {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-top: 12px;
}

.platform-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 8px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s;
}

.platform-item.active {
  border-color: #4caf50;
  background: rgba(76, 175, 80, 0.05);
}

.platform-item:hover:not(.active) {
  border-color: #ccc;
}

.platform-icon {
  font-size: 24px;
  margin-bottom: 4px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
}

.platform-icon.wechat {
  background: #07c160;
  color: white;
}

.platform-icon.alipay {
  background: #1677ff;
  color: white;
}

.platform-icon.douyin {
  background: #ff0050;
  color: white;
}

.platform-item span {
  font-size: 12px;
  color: #666;
  text-align: center;
}

.size-input {
  display: flex;
  align-items: center;
  gap: 8px;
}

.size-input input {
  flex: 1;
  width: auto !important;
}

.size-input span {
  color: #6b7280;
  font-size: 14px;
}

.preview-panel {
  flex: 0 0 50%;
  width: 50%;
  background: white;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.preview-content {
  flex: 1;
  padding: 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  overflow: hidden;
  background-color: rgba(30, 31, 34, 0.03);
}

.preview-header {
  text-align: center;
  margin: 0;
}

.preview-header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
  color: #333;
}

.payment-preview {
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 1;
}

.canvas-container {
  display: flex;
  justify-content: center;
  align-items: center;
  max-width: 100%;
  max-height: 100%;
}

.payment-canvas {
  border-radius: 0;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  background: #ffffff;
  cursor: pointer;
  transition: transform 0.2s ease;
  max-width: 300px;
  max-height: 480px;
}

.payment-canvas:hover {
  transform: scale(1.02);
}

.action-buttons {
  display: flex;
  gap: 12px;
}

.download-btn {
  padding: 10px 16px;
  background: #f9f9f9;
  color: #666;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  font-weight: normal;
  cursor: pointer;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  gap: 6px;
}

.download-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.download-btn:not(:disabled):hover {
  background: #f0f0f0;
  border-color: #ccc;
}

@media (max-width: 1024px) {
  .qr-generator {
    flex-direction: column;
    height: auto;
    min-height: 100vh;
  }

  .config-panel {
    width: 100%;
    max-height: 60vh;
  }

  .qr-preview {
    width: 280px;
    height: 280px;
  }
}
</style>
